package com.jk.lesson7;

import java.util.Date;
import java.util.function.Function;
import java.util.stream.LongStream;
import java.util.stream.Stream;

/**
 * Created by Auser on 2017/3/14.
 */
public class lesson7_1 {
    public static void main(String[] args) {
//        System.out.println("Sequential sum done in : " +
//                measureSumPerf(lesson7_1::sequentialSum, 100_000_000) + " ms");
//        System.out.println("Parallel sum done in : " +
//                measureSumPerf(lesson7_1::parallelSum, 100_000_000) + " ms");

        System.out.println("SequentialRange sum done in : " +
                measureSumPerf(lesson7_1::sequentialRangedSum, 100_000_000) + " ms");
        System.out.println("ParallelRange sum done in : " +
                measureSumPerf(lesson7_1::parallelRangedSum, 100_000_000) + " ms");
    }

    /**
     * 顺序流
     * @param n
     * @return
     */
    public static long sequentialSum(long n){
        return Stream.iterate(1L, i -> i + 1)   // 自然数，无限流
                .limit(n)   // 前N位
                .reduce(0L, Long::sum); // 规约求和
    }

    /**
     * 顺序流：rangeClosed
     * @param n
     * @return
     */
    public static long sequentialRangedSum(long n){
        return LongStream.rangeClosed(1, n)
                .reduce(0L, Long::sum); // 规约求和
    }


    /**
     * 并行流
     * @param n
     * @return
     */
    public static long parallelSum(long n){
        return Stream.iterate(1L, i -> i + 1 )
                .limit(n)
                .parallel()
                .reduce(0L, Long::sum);
    }

    /**
     * 并行流:rangeClosed
     * @param n
     * @return
     */
    public static long parallelRangedSum(long n){
        return LongStream.rangeClosed(1, n)
                .parallel()
                .reduce(0L, Long::sum);
    }

    public static long measureSumPerf(Function<Long, Long> adder, long n) {
        long fastest = Long.MAX_VALUE;
        for (int i = 0; i < 10 ; i++){
            long start = System.nanoTime();
            long sum = adder.apply(n);
            long duration = (System.nanoTime() - start) / 1_000_000;
            System.out.println("Result: " + sum);
            if (duration < fastest)
                fastest = duration;
        }
        return  fastest;
    }
}
